package repositories

import (
	"context"
	"github.com/pkg/errors"
	"go.didapinche.com/foundation/plat-echo/app/ops/models"
	time2 "go.didapinche.com/time"
	"gorm.io/gorm"
	"strconv"
)

type GraphRepository interface {
	Create(ctx context.Context, graph *models.Graph) (*models.Graph, error)
	Creates(ctx context.Context, graph []*models.Graph) error
	Save(ctx context.Context, graph *models.Graph) (*models.Graph, error)
	UpdateIsForceByTemplateID(ctx context.Context, template_id uint64, SubscribeType, level []int, contain bool) error
	Delete(ctx context.Context, id uint64) error
	DeleteByApiID(ctx context.Context, ids []uint64) error
	DeleteHost(ctx context.Context) error
	DeleteByTemplateID(ctx context.Context, templateID uint64) error
	FindByID(ctx context.Context, id uint64) (*models.Graph, error)
	FindByTemplateID(ctx context.Context, templateID uint64) ([]*models.Graph, error)
	FindByTemplateIDAndIDAndKind(ctx context.Context, templateID, id, kind uint64) (*models.Graph, error)
	FindByKindAndID(ctx context.Context, id, kind int) ([]*models.Graph, error)
	DeleteByDashboardID(ctx context.Context, id uint64) error
	FindByApiIDAndIsForce(ctx context.Context, id uint64) ([]*models.Graph, error)
	FindGraphByAppID(ctx context.Context, appID uint64) ([]*models.GraphAndType, error)
	FindGraphByHostID(ctx context.Context, hostID uint64) ([]*models.GraphAndType, error)
	FindGraphByApiID(ctx context.Context, apiID uint64) ([]*models.GraphAndType, error)
	UpdateGraphByAppID(ctx context.Context, appID uint64, owner string, level int) error
	UpdateGraphByApiID(ctx context.Context, apiID []uint64, owner string, level int) error
	FindGraphByApiIDAndTemplateID(ctx context.Context, apiID, templateID uint64) (*models.Graph, error)
	FindGraphByDashboardID(ctx context.Context, dashboardIDs []uint64) ([]*models.GraphAndType, error)
}

type graphRepository struct {
	db *gorm.DB
}

func NewGraphRepository(db *gorm.DB) GraphRepository {
	return &graphRepository{
		db: db,
	}
}

// 每次创建都需要同步k8s
func (r graphRepository) Create(ctx context.Context, graph *models.Graph) (*models.Graph, error) {
	graph.CreateTime = time2.Now()
	graph.UpdateTime = time2.Now()
	if err := r.db.WithContext(ctx).Table(models.GraphTableName).Create(graph).Error; err != nil {
		return nil, errors.Wrap(err, "create Graph error")
	}
	return graph, nil
}
func (r graphRepository) Creates(ctx context.Context, graph []*models.Graph) error {
	if err := r.db.WithContext(ctx).Table(models.GraphTableName).CreateInBatches(&graph, 1000).Error; err != nil {
		return errors.Wrap(err, "create Graph error")
	}
	return nil
}

func (r graphRepository) Save(ctx context.Context, graph *models.Graph) (*models.Graph, error) {
	graph.UpdateTime = time2.Now()
	if err := r.db.WithContext(ctx).Table(models.GraphTableName).Save(graph).Error; err != nil {
		return nil, errors.Wrap(err, "Save graph error")
	}
	return graph, nil
}

func (r graphRepository) Delete(ctx context.Context, id uint64) error {
	if err := r.db.WithContext(ctx).Table(models.GraphTableName).Delete(&models.Graph{}, id).Error; err != nil {
		return errors.Wrap(err, "Delete graph error")
	}
	return nil
}
func (r graphRepository) DeleteByApiID(ctx context.Context, ids []uint64) error {
	if err := r.db.WithContext(ctx).Table(models.GraphTableName).Where("api_id in ?", ids).Delete(&models.Graph{}).Error; err != nil {
		return errors.Wrap(err, "Delete graph error")
	}
	return nil
}
func (r graphRepository) DeleteHost(ctx context.Context) error {
	if err := r.db.WithContext(ctx).Table(models.GraphTableName).Where("host_id>0").Delete(&models.Graph{}).Error; err != nil {
		return errors.Wrap(err, "Delete graph host error")
	}
	return nil
}

func (r graphRepository) UpdateIsForceByTemplateID(ctx context.Context, templateID uint64, SubscribeType, level []int, contain bool) error {
	if contain {
		if err := r.db.WithContext(ctx).Exec("update  t_graph set subscribe=json_set(subscribe,'$.subscribe_force',JSON_ARRAY?) where template_id=? and level in ?", SubscribeType, templateID, level).Error; err != nil {
			return errors.Wrap(err, "call UpdateIsForceByTemplateID error")
		}
	} else {
		if err := r.db.WithContext(ctx).Exec("update  t_graph set subscribe=json_set(subscribe,'$.subscribe_force',JSON_ARRAY?) where template_id=? and level not in ?", SubscribeType, templateID, level).Error; err != nil {
			return errors.Wrap(err, "call UpdateIsForceByTemplateID error")
		}
	}
	return nil
}

func (r graphRepository) DeleteByTemplateID(ctx context.Context, templateID uint64) error {
	if err := r.db.WithContext(ctx).Table(models.GraphTableName).Where("template_id=?", templateID).Delete(&models.Graph{}).Error; err != nil {
		return errors.Wrap(err, "Delete graph error")
	}
	return nil
}

func (r graphRepository) DeleteByDashboardID(ctx context.Context, id uint64) error {
	if err := r.db.WithContext(ctx).Table(models.GraphTableName).Where("dashboard_id =?", id).Delete(&models.Graph{}).Error; err != nil {
		return errors.Wrap(err, "Delete graph error")
	}
	return nil
}

func (r graphRepository) FindByID(ctx context.Context, id uint64) (*models.Graph, error) {
	graph := new(models.Graph)
	if err := r.db.WithContext(ctx).Table(models.GraphTableName).First(graph, "id =?", id).Error; err != nil {
		return nil, errors.Wrap(err, "FindByID graph error")
	}
	return graph, nil
}

func (r graphRepository) FindByTemplateID(ctx context.Context, templateID uint64) ([]*models.Graph, error) {
	graphs := make([]*models.Graph, 0)
	if err := r.db.WithContext(ctx).Table(models.GraphTableName).Find(&graphs, "template_id =?", templateID).Error; err != nil {
		return nil, errors.Wrap(err, "FindByTemplateID graph error")
	}
	return graphs, nil
}

func (r graphRepository) FindByKindAndID(ctx context.Context, id, kind int) ([]*models.Graph, error) {
	query := ""
	if kind == 0 {
		query = " kind=0 and app_id=" + strconv.Itoa(id)
	} else if kind == 1 {
		query = " kind=1 and api_id=" + strconv.Itoa(id)
	} else if kind == 2 {
		query = " kind=2 and host_id=" + strconv.Itoa(id)
	} else if kind == 3 {
		query = " kind=3 and dashboard_id=" + strconv.Itoa(id)
	}
	graphs := make([]*models.Graph, 0)
	if err := r.db.WithContext(ctx).Table(models.GraphTableName).Find(&graphs, query).Error; err != nil {
		return nil, errors.Wrap(err, "FindByKindAndID graph error")
	}
	return graphs, nil
}
func (r graphRepository) FindByApiIDAndIsForce(ctx context.Context, id uint64) ([]*models.Graph, error) {
	graphs := make([]*models.Graph, 0)
	if err := r.db.WithContext(ctx).Table(models.GraphTableName).Find(&graphs, "api_id=? and is_force=0", id).Error; err != nil {
		return nil, errors.Wrap(err, "FindByApiIDAndIsForce graph error")
	}
	return graphs, nil
}
func (r graphRepository) FindByTemplateIDAndIDAndKind(ctx context.Context, templateID, id, kind uint64) (*models.Graph, error) {
	query := ""
	if kind == 0 {
		query = " kind=0 and app_id=" + strconv.Itoa(int(id)) + " and template_id=" + strconv.Itoa(int(templateID))
	} else if kind == 1 {
		query = " kind=1 and api_id=" + strconv.Itoa(int(id)) + " and template_id=" + strconv.Itoa(int(templateID))
	} else if kind == 2 {
		query = " kind=2 and host_id=" + strconv.Itoa(int(id)) + " and template_id=" + strconv.Itoa(int(templateID))
	} else if kind == 3 {
		query = " kind=3 and dashboard_id=" + strconv.Itoa(int(id)) + " and template_id=" + strconv.Itoa(int(templateID))
	}
	graph := new(models.Graph)
	if err := r.db.WithContext(ctx).Table(models.GraphTableName).First(graph, query).Error; err != nil {
		return nil, errors.Wrap(err, "FindByKindAndID graph error")
	}
	return graph, nil
}

func (r graphRepository) FindGraphByAppID(ctx context.Context, appID uint64) ([]*models.GraphAndType, error) {
	graphs := make([]*models.GraphAndType, 0)
	if err := r.db.WithContext(ctx).Raw("select g.*,t.order order2,t.name type_name,t.key `key` from t_temp_type t ,t_graph g  where g.type_id=t.id and g.app_id=?", appID).Scan(&graphs).Error; err != nil {
		return nil, errors.Wrap(err, "call FindGraphByAppID error ")
	}
	return graphs, nil
}

func (r graphRepository) FindGraphByApiID(ctx context.Context, apiID uint64) ([]*models.GraphAndType, error) {
	graphs := make([]*models.GraphAndType, 0)
	if err := r.db.WithContext(ctx).Raw("select g.*,t.order order2,t.name type_name,t.key `key` from t_temp_type t ,t_graph g  where g.type_id=t.id and g.api_id=?", apiID).Scan(&graphs).Error; err != nil {
		return nil, errors.Wrap(err, "call FindGraphByApiID error ")
	}
	return graphs, nil
}

func (r graphRepository) FindGraphByApiIDAndTemplateID(ctx context.Context, apiID, templateID uint64) (*models.Graph, error) {
	graph := new(models.Graph)
	if err := r.db.WithContext(ctx).Table(models.GraphTableName).First(graph, "api_id =? and template_id=?", apiID, templateID).Error; err != nil {
		return nil, errors.Wrap(err, "FindByID graph error")
	}
	return graph, nil
}
func (r graphRepository) FindGraphByDashboardID(ctx context.Context, dashboardIDs []uint64) ([]*models.GraphAndType, error) {
	graphs := make([]*models.GraphAndType, 0)
	if err := r.db.WithContext(ctx).Raw("select g.*,t.name type_name,t.id type_id from t_dashboard t ,t_graph g  where  g.dashboard_id in ? and g.dashboard_id=t.id", dashboardIDs).Scan(&graphs).Error; err != nil {
		return nil, errors.Wrap(err, "call FindGraphByDashboardID error ")
	}
	return graphs, nil
}

func (r graphRepository) FindGraphByHostID(ctx context.Context, hostID uint64) ([]*models.GraphAndType, error) {
	graphs := make([]*models.GraphAndType, 0)
	if err := r.db.WithContext(ctx).Raw("select g.*,t.order order2,t.name type_name,t.key `key` from t_temp_type t ,t_graph g  where g.type_id=t.id and g.host_id=?", hostID).Scan(&graphs).Error; err != nil {
		return nil, errors.Wrap(err, "call FindGraphByDashboardID error ")
	}
	return graphs, nil
}
func (r graphRepository) UpdateGraphByAppID(ctx context.Context, appID uint64, owner string, level int) error {
	if err := r.db.WithContext(ctx).Exec("update  t_graph set alert=json_set(alert,'$.receiver.users',JSON_ARRAY('?')),level=? where app_id=?", owner, level, appID).Error; err != nil {
		return err
	}
	return nil
}

func (r graphRepository) UpdateGraphByApiID(ctx context.Context, apiID []uint64, owner string, level int) error {
	if err := r.db.WithContext(ctx).Exec("update  t_graph set alert=json_set(alert,'$.receiver.users',JSON_ARRAY('?')),level=? where api_id in ?", owner, level, apiID).Error; err != nil {
		return err
	}
	return nil
}
